home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / utilities / bmfc000.lha / BMFC / src / bmfc / build.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-31  |  17.0 KB  |  578 lines

  1. /**************************************/
  2. /* build.c                            */
  3. /* for BMFC 0.00                      */
  4. /* Copyright 1992 by Adam M. Costello */
  5. /**************************************/
  6.  
  7.  
  8. #include <limits.h>
  9.  
  10. #if UCHAR_MAX != 255
  11. #error ---------------------------------------
  12. #error Danger!  Danger!  UCHAR_MAX is not 255!
  13. #error ---------------------------------------
  14. #endif
  15.  
  16. #include "build.h"  /* Makes sure we're consistent with the    */
  17.                     /* prototypes and also includes <stdio.h>. */
  18. #include "parse.h"
  19. #include "error.h"
  20. #include <stdlib.h>
  21.  
  22.  
  23. static void checkgeneric(enum paramindex);
  24. static void checkbaseline(enum paramindex);
  25. static void checkhigh(enum paramindex);
  26. static void checklow(enum paramindex);
  27. static void checkproportional(enum paramindex);
  28. static void checkxsize(enum paramindex);
  29.  
  30. static void (*const paramchecker[])(enum paramindex) = {
  31.   checkgeneric, checkbaseline, checkgeneric, checkgeneric, checkgeneric,
  32.   checkgeneric, checkgeneric, checkgeneric, checkgeneric, checkhigh,
  33.   checkgeneric, checklow, checkgeneric, checkgeneric, checkproportional,
  34.   checkgeneric, checkgeneric, checkgeneric, checkgeneric, checkgeneric,
  35.   checkgeneric, checkxsize
  36. };
  37.  
  38. #define check(param)  { paramchecker[param](param); }
  39.  
  40. static struct font    *thefont;
  41. static unsigned long  *theparams;
  42. static unsigned char **theglyphs;
  43. static unsigned short *thewidths;
  44.  
  45. enum instrindex {
  46.   bitmapfont, xydpi, colors, colorsym, glyph, nullglyph, numinstrs
  47. };
  48.  
  49. static void readbitmapfont(void);
  50. static void readxydpi(void);
  51. static void readcolors(void);
  52. static void readcolorsym(void);
  53. static void readglyph(void);
  54. static void readnullglyph(void);
  55.  
  56. static void (*const instrreader[])(void) = {
  57.   readbitmapfont, readxydpi, readcolors, readcolorsym, readglyph, readnullglyph
  58. };
  59.  
  60. /* Some parameters have constant min/max and/or default values: */
  61.  
  62. #define special  0           /* So humans can tell which don't. */
  63.  
  64. static const unsigned long parammin[] = {
  65. /* antialias baseline bold boldsmear colorfont depth extended fgcolor    */
  66.            0, special,   0,        0,        0,    1,       0,      0,
  67. /* greyfont     high italic      low planeonoff planepick proportional   */
  68.           0, special,     0, special,         0,        0,           0,
  69. /* returncode revision revpath talldot underlined widedot    xsize       */
  70.             0,       0,      0,      0,         0,      0,       0
  71. };
  72.  
  73. static const unsigned long parammax[] = {
  74. /* antialias baseline bold boldsmear colorfont depth extended fgcolor    */
  75.            1, special,   1,    65535,        1,    8,       1,    255,
  76. /* greyfont     high italic      low planeonoff planepick proportional   */
  77.           1, special,     1, special,       255,      255,           1,
  78. /* returncode revision revpath talldot underlined widedot    xsize       */
  79.           127,   65535,      1,      1,         1,      1,   65535
  80. };
  81.  
  82. static const unsigned long paramdefault[] = {
  83. /* antialias baseline bold boldsmear colorfont depth extended fgcolor    */
  84.            0, special,   0,        1,        0,    1,       0,    255,
  85. /* greyfont     high italic      low planeonoff planepick proportional   */
  86.           0, special,     0, special,         0,      255,     special,
  87. /* returncode revision revpath talldot underlined widedot    xsize       */
  88.           100,       0,      0,      0,         0,      0, special
  89. };
  90.  
  91. /* Some parameters apply only to color fonts: */
  92.  
  93. static const boolean colorparam[] =
  94.   { 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
  95.  
  96. enum assignstatus { unassigned, assigned, checked, defaulted };
  97.  
  98. /* Note, the above is a progression.  That is,       */
  99. /* defaulted implies checked which implies assigned. */
  100.  
  101. static enum assignstatus paramstatus[numparams];
  102.  
  103. static unsigned char map[UCHAR_MAX + 1];
  104.  
  105. static const char
  106.  
  107.   /* Error messages: */ 
  108.  
  109.   *const bmfexpected   = "Instruction bitmapfont expected.\n",
  110.   *const intexpected   = "Integer expected.\n",
  111.   *const badysize      = "ysize is out of range [1,65535].\n",
  112.   *const toomanywords  = "Too many words for this instruction.\n",
  113.   *const toofewwords   = "Too few words for this instruction.\n",
  114.   *const unknowninstr  = "Unknown instruction: %s\n",
  115.   *const noglyph256    = "Glyph 256 not defined.\n",
  116.   *const norealglyphs  = "No glyphs defined (except glyph 256).\n",
  117.   *const paramrange    = "Parameter %s is out of range [%u,%u].\n",
  118.   *const customprange  = "Parameter %s is out of range [%s].\n",
  119.   *const badglyphcolor = "Glyph %u uses color %u > 2^depth - 1.\n",
  120.   *const instragain    = "Instruction %s used more than once.\n",
  121.   *const paramagain    = "Parameter %s assigned more than once.\n",
  122.   *const dpirange      = "dpi value out of range [1,32767].\n",
  123.   *const toomanycolors = "At most 256 colors may be defined.\n",
  124.   *const colortoobig   = "An RGB color value exceeded $FFF.\n",
  125.   *const onecharexp    = "This word must have length 1.\n",
  126.   *const colornumrange = "Color number out of range [0,255].\n",
  127.   *const glyphrange    = "Glyph number out of range [0,256].\n",
  128.   *const glyphorder    = "Second glyph number is less than first.\n",
  129.   *const glyphagain    = "Glyph %u defined twice.\n",
  130.   *const glyphwidth    = "Rows of glyph %u not all same width.\n",
  131.  
  132.   /* Warning messages: */
  133.  
  134.   *const nametrunc    = "name \"%s\" truncated to \"%.32s\".\n",
  135.   *const noteparam    = "(note parameter %s = %lu)\n",
  136.   *const paramdefto   = "Parameter %s defaults to %lu.\n",
  137.   *const mootparam    = "Parameter %s was assigned, but is ignored.\n",
  138.   *const mootinstr    = "Instruction %s was issued, but doesn't apply.\n";
  139.  
  140. static const unsigned char
  141.  
  142.   /* Instruction names: Must be in same order as in enum instrindex. */
  143.  
  144.   *const instrname[] = {
  145.     "bitmapfont", "xydpi", "colors", "colorsym", "glyph", "nullglyph"
  146.   },
  147.  
  148.   /* Parameter names: Must be in same order as in enum paramindex. */
  149.  
  150.   *const paramname[] = {
  151.     "antialias", "baseline", "bold", "boldsmear", "colorfont", "depth",
  152.     "extended", "fgcolor", "greyfont", "high", "italic", "low", "planeonoff",
  153.     "planepick", "proportional", "returncode", "revision", "revpath",
  154.     "talldot", "underlined", "widedot", "xsize"
  155.   };
  156.  
  157.  
  158. static unsigned long getul(void)  /* Reads next word and returns value. */
  159. {                                 /* Doesn't return if unsuccessful.    */
  160.   const unsigned char *word;
  161.   unsigned long ul;
  162.  
  163.   word = nextword();
  164.   if (!*word) parsefailf(toofewwords);
  165.   if (!wordtoul(word,&ul)) parsefailf(intexpected);
  166.   return ul;
  167. }
  168.  
  169.  
  170. static int streq(const unsigned char *s1, const unsigned char *s2)
  171. /* Returns 1 if strings s1 and s2 are equal, 0 otherwise. */
  172. /* s1 and s2 must both point to '\0'-terminated strings.  */
  173. {
  174.   while (*s1) {
  175.     if (*s1 != *s2) return 0;
  176.     ++s1;
  177.     ++s2;
  178.   }
  179.   return (*s2 == '\0');
  180. }
  181.  
  182.  
  183. static void readparam(unsigned long param)  /* Reads the value of param. */
  184. {
  185.   if (paramstatus[param] >= assigned) parsefailf(paramagain, paramname[param]);
  186.   theparams[param] = getul();
  187.   if (*nextword()) parsefailf(toomanywords);
  188.   paramstatus[param] = assigned;
  189. }
  190.  
  191.  
  192. void build(FILE *srcfile, struct font *f)  /* This is long, but not deep. */
  193. {
  194.   const unsigned char *word;
  195.   enum assignstatus *pstat, *laststat;
  196.   unsigned char *ppix, *lastpix, **pglyph, **lastglyph;
  197.   unsigned short *pwidth;
  198.   int i,j;
  199.   unsigned long ys;
  200.   enum instrindex instr;
  201.   enum paramindex param;
  202.   boolean cf;
  203.   unsigned char maxcolor;
  204.  
  205.   thefont   = f;
  206.   theparams = f->parameters;
  207.   theglyphs = f->glyphs;
  208.   thewidths = f->widths;
  209.  
  210.   for (pstat = paramstatus, laststat = paramstatus + numparams;
  211.        pstat < laststat;
  212.        *pstat++ = unassigned);                /* Initialize parameter stati. */
  213.  
  214.   for (pglyph = theglyphs, lastglyph = theglyphs + 256;
  215.        pglyph <= lastglyph;
  216.        *pglyph++ = NULL);                     /* Clear glyph pointers.       */
  217.  
  218.   for (ppix = map, lastpix = map + UCHAR_MAX;
  219.        ppix <= lastpix;
  220.        *ppix++ = 0);                          /* Clear color symbol map.     */
  221.  
  222.   map['@'] = map['#'] = map['*'] = map['1'] = 1;
  223.   map['2'] = 2;
  224.   map['3'] = 3;
  225.   map['4'] = 4;
  226.   map['5'] = 5;
  227.   map['6'] = 6;
  228.   map['7'] = 7;
  229.   map['8'] = 8;
  230.   map['9'] = 9;
  231.   map['A'] = map['a'] = 10;
  232.   map['B'] = map['b'] = 11;
  233.   map['C'] = map['c'] = 12;
  234.   map['D'] = map['d'] = 13;
  235.   map['E'] = map['e'] = 14;
  236.   map['F'] = map['f'] = 15;
  237.  
  238.   thefont->usedcolors = 0;
  239.   thefont->usedxydpi = 0;
  240.  
  241.   beginparsing(srcfile);
  242.   word = nextword();
  243.   if (!streq(word, instrname[bitmapfont])) parsefailf(bmfexpected);
  244.   word = nextword();
  245.   for (i = 0; i < 32 && word[i]; ++i) thefont->name[i] = word[i];
  246.   if (i == 32 && word[32]) warnf(nametrunc,word,word);
  247.   for (j = i; j < 32; ++j) thefont->name[j] = 0;
  248.   ys = getul();
  249.   if (ys < 1 || ys > 65535) parsefailf(badysize);
  250.   thefont->ysize = ys;
  251.   if (*nextword()) parsefailf(toomanywords);
  252.  
  253.   while (nextinstr()) {
  254.  
  255.     word = nextword();
  256.     if (!*word) continue;
  257.     for (instr = 0; instr < numinstrs; ++instr)
  258.       if (streq(word,instrname[instr])) {
  259.         instrreader[instr]();
  260.         break;
  261.       }
  262.     if (instr < numinstrs) continue;
  263.     for (param = 0; param < numparams; ++param)
  264.       if (streq(word,paramname[param])) {
  265.         readparam(param);
  266.         break;
  267.       }
  268.     if (param < numparams) continue;
  269.     parsefailf(unknowninstr,word);
  270.  
  271.   }
  272.  
  273.   if (!theglyphs[256]) failf(noglyph256);
  274.   for (pglyph = theglyphs; !*pglyph; ++pglyph);
  275.   if (pglyph == theglyphs + 256) failf(norealglyphs);
  276.  
  277.   for (param = 0; param < numparams; ++param) check(param);
  278.  
  279.   cf = theparams[colorfont];
  280.   maxcolor = cf ? ((1 << theparams[depth]) - 1) : 1;
  281.  
  282.   for (pglyph = theglyphs, pwidth = thewidths, lastglyph = theglyphs + 257;
  283.        pglyph < lastglyph;
  284.        ++pglyph, ++pwidth)
  285.     if (*pglyph)
  286.       for (ppix = *pglyph, lastpix = ppix + ys * (unsigned long) *pwidth;
  287.            ppix < lastpix;
  288.            ++ppix)
  289.         if (*ppix > maxcolor) {
  290.           warnf(noteparam, paramname[depth], theparams[depth]);
  291.           failf(badglyphcolor, pglyph - theglyphs, *ppix);
  292.         }
  293.  
  294.   for (param = 0; param < numparams; ++param)
  295.     if (paramstatus[param] >= defaulted && (!colorparam[param] || cf))
  296.       warnf(paramdefto, paramname[param], theparams[param]);
  297.  
  298.   if (!cf)
  299.     for (param = 0; param < numparams; ++param)
  300.       if (colorparam[param] && paramstatus[param] < defaulted)
  301.         warnf(mootparam, paramname[param]);
  302.  
  303.   if (thefont->usedcolors) {
  304.     if (!cf) warnf(mootinstr, instrname[colors]);
  305.   } else thefont->numcolors = 0;
  306. }
  307.  
  308.  
  309. static void readbitmapfont(void)
  310. {
  311.   parsefailf(instragain, instrname[bitmapfont]);
  312. }
  313.  
  314.  
  315. static void readxydpi(void)
  316. {
  317.   unsigned long dpi;
  318.  
  319.   if (thefont->usedxydpi) parsefailf(instragain, instrname[xydpi]);
  320.   thefont->usedxydpi = 1;
  321.  
  322.   dpi = getul();
  323.   if (dpi < 1 || dpi > 32767) parsefailf(dpirange);
  324.   thefont->xdpi = dpi;
  325.  
  326.   dpi = getul();
  327.   if (dpi < 1 || dpi > 32767) parsefailf(dpirange);
  328.   thefont->ydpi = dpi;
  329.  
  330.   if (*nextword) parsefailf(toomanywords);
  331. }
  332.  
  333.  
  334. static void readcolors(void)
  335. {
  336.   unsigned long nc, c;
  337.   int i;
  338.  
  339.   if (thefont->usedcolors) parsefailf(instragain, instrname[colors]);
  340.   thefont->usedcolors = 1;
  341.  
  342.   nc = getul();
  343.   if (nc > 256) parsefailf(toomanycolors);
  344.   thefont->numcolors = nc;
  345.  
  346.   for (i = 0; i < nc; ++i) {
  347.     c = getul();
  348.     if (c > 0xFFF) parsefailf(colortoobig);
  349.     thefont->colorvals[i] = c;
  350.   }
  351.  
  352.   if (*nextword()) parsefailf(toomanywords);
  353. }
  354.  
  355.  
  356. static void readcolorsym(void)
  357. {
  358.   const unsigned char *word;
  359.   unsigned char sym;
  360.   unsigned long cn;
  361.  
  362.   word = nextword();
  363.   if (!*word) parsefailf(toofewwords);
  364.   if (word[1]) parsefailf(onecharexp);
  365.   sym = *word;
  366.   cn = getul();
  367.   if (cn > 255) parsefailf(colornumrange);
  368.   map[sym] = cn;
  369. }
  370.  
  371.  
  372. static int slen(const unsigned char *s)  /* Returns length of string s,    */
  373. {                                        /* which must be '\0'-terminated. */
  374.   const unsigned char *p = s;
  375.  
  376.   while (*p) ++p;
  377.   return p - s;
  378. }
  379.  
  380.  
  381. static unsigned char *allocglyph(unsigned short width)
  382. /* Allocates memory for a glyph given its width.  Returns a */
  383. /* pointer to the glyph.  Doesn't return if unsuccessful.   */
  384. {
  385.   unsigned short ys = thefont->ysize;
  386.   unsigned char *g;
  387.  
  388.   g = (unsigned char *) malloc(ys * width * sizeof (unsigned char));
  389.   if (!g) failf(outofmem);
  390.   return g;
  391. }
  392.  
  393.  
  394. static void readglyph(void)
  395. {
  396.   const unsigned char *word;
  397.   unsigned char *ppix, *lastpix, **pglyph, **lastglyph;
  398.   unsigned long first, last;
  399.   int row, w;
  400.   unsigned short ys = thefont->ysize, *pwidth;
  401.  
  402.   first = getul();
  403.   if (first > 256) parsefailf(glyphrange);
  404.   last = getul();
  405.   if (last > 256) parsefailf(glyphrange);
  406.   if (last < first) parsefailf(glyphorder);
  407.  
  408.   for (pglyph = theglyphs + first, pwidth = thewidths + first,
  409.          lastglyph = theglyphs + last;
  410.        pglyph <= lastglyph;
  411.        ++pglyph, ++pwidth) {
  412.     if (*pglyph) parsefailf(glyphagain, pglyph - theglyphs);
  413.     word = nextword();
  414.     if (!*word) parsefailf(toofewwords);
  415.     *pwidth = w = slen(word);
  416.     *pglyph = allocglyph(w);
  417.     for (ppix = *pglyph, lastpix = ppix + w;
  418.          ppix < lastpix;
  419.          ++ppix, ++word)
  420.       *ppix = map[*word];
  421.   }
  422.  
  423.   for (row = 1; row < ys; ++row)
  424.     for (pglyph = theglyphs + first, pwidth = thewidths + first,
  425.            lastglyph = theglyphs + last;
  426.          pglyph <= lastglyph;
  427.          ++pglyph, ++pwidth) {
  428.       word = nextword();
  429.       if (!*word) parsefailf(toofewwords);
  430.       w = *pwidth;
  431.       if (slen(word) != w) parsefailf(glyphwidth, pglyph - theglyphs);
  432.       for (ppix = *pglyph + row * w, lastpix = ppix + w;
  433.            ppix < lastpix;
  434.            ++ppix, ++word)
  435.         *ppix = map[*word];
  436.     }
  437.  
  438.   if (*nextword()) parsefailf(toomanywords);
  439. }
  440.  
  441.  
  442. static void readnullglyph(void)
  443. {
  444.   /* Defined glyphs can't be NULL, so here's a place for them to point: */
  445.   static unsigned char *nullgmarker = "";
  446.   unsigned char **pglyph, **lastglyph;
  447.   unsigned short *pwidth;
  448.   unsigned long first, last;
  449.  
  450.   first = getul();
  451.   if (first > 256) parsefailf(glyphrange);
  452.   last = getul();
  453.   if (last > 256) parsefailf(glyphrange);
  454.   if (last < first) parsefailf(glyphorder);
  455.   if (*nextword()) parsefailf(toomanywords);
  456.  
  457.   for (pglyph = theglyphs + first, pwidth = thewidths + first,
  458.          lastglyph = theglyphs + last;                           
  459.        pglyph <= lastglyph;                          
  460.        ++pglyph, ++pwidth) {                        
  461.     *pglyph = nullgmarker;
  462.     *pwidth = 0;
  463.   }
  464. }
  465.  
  466.  
  467. static void checkgeneric(enum paramindex param)
  468. {
  469.   if (paramstatus[param] < assigned) {
  470.     theparams[param] = paramdefault[param];
  471.     paramstatus[param] = defaulted;
  472.   } else if (paramstatus[param] < checked) {
  473.     if (   theparams[param] > parammax[param]
  474.         || theparams[param] < parammin[param])
  475.       failf(paramrange, paramname[param], parammin[param], parammax[param]);
  476.     paramstatus[param] = checked;
  477.   }
  478. }
  479.  
  480.  
  481. static void checkbaseline(enum paramindex param)  /* param must be baseline */
  482. {
  483.   unsigned long ys = thefont->ysize;
  484.  
  485.   if (paramstatus[param] < assigned) {                                   
  486.     theparams[param] = (ys > 1) ? (ys - 2) : 0;
  487.     paramstatus[param] = defaulted;  
  488.   } else if (paramstatus[param] < checked) {    
  489.     if (theparams[param] > ys - 1)  
  490.       failf(customprange, paramname[param], "0, <ysize> - 1");
  491.     paramstatus[param] = checked;       
  492.   }
  493. }
  494.  
  495.  
  496. static void checkhigh(enum paramindex param)  /* param must be high */
  497. {
  498.   unsigned long d;
  499.   unsigned char m;
  500.  
  501.   check(depth);
  502.   check(low);
  503.  
  504.   d = theparams[depth];
  505.   m = (1 << d) - 1;
  506.  
  507.   if (paramstatus[param] < assigned) {
  508.     theparams[param] = m;
  509.     paramstatus[param] = defaulted;
  510.   } else if (paramstatus[param] < checked)
  511.     if (theparams[high] < theparams[low] || theparams[high] > m) {
  512.       warnf(noteparam, paramname[low], theparams[low]);
  513.       warnf(noteparam, paramname[depth], d);
  514.       failf(customprange, paramname[high], "low, 2^depth - 1");
  515.     }
  516. }
  517.  
  518.  
  519. static void checklow(enum paramindex param)  /* param must be low */
  520. {
  521.   unsigned long d;
  522.   unsigned char m;
  523.  
  524.   check(depth);
  525.  
  526.   d = theparams[depth];
  527.   m = (1 << d) - 1;
  528.  
  529.   if (paramstatus[low] < assigned) {
  530.     theparams[low] = 0;
  531.     paramstatus[low] = defaulted;
  532.   } else if (paramstatus[low] < checked) {
  533.     if (theparams[low] > m) {
  534.       warnf(noteparam, paramname[depth], d);
  535.       failf(customprange, paramname[low], "0, 2^depth - 1");
  536.     }
  537.     paramstatus[low] = checked;
  538.   }
  539. }
  540.  
  541.  
  542. static void checkproportional(enum paramindex param)  /* param must be */
  543. {                                                     /* proportional  */
  544.   checkgeneric(param);
  545.  
  546.   if (paramstatus[param] >= defaulted) {
  547.  
  548.     unsigned short w = thewidths[256], *pwidth, *lastwidth;
  549.     unsigned char **pglyph;
  550.  
  551.     for (pwidth = thewidths, pglyph = theglyphs, lastwidth = thewidths + 256;
  552.          pwidth < lastwidth;
  553.          ++pwidth, ++pglyph)
  554.       if (*pglyph && *pwidth != w) break;
  555.     theparams[proportional] = (pwidth < lastwidth) ? 1 : 0;
  556.  
  557.   }
  558. }
  559.  
  560.  
  561. static void checkxsize(enum paramindex param)  /* param must be xsize */
  562. {
  563.   checkgeneric(xsize);
  564.  
  565.   if (paramstatus[param] >= defaulted) {
  566.  
  567.     unsigned char **pglyph;
  568.     unsigned short x = 0, *pwidth, *lastwidth;
  569.  
  570.     for (pwidth = thewidths, pglyph = theglyphs, lastwidth = thewidths + 257;
  571.          pwidth < lastwidth;
  572.          ++pwidth, ++pglyph)
  573.       if (*pglyph && *pwidth > x) x = *pwidth;
  574.     theparams[xsize] = x;
  575.  
  576.   }
  577. }
  578.